package com.funteam.funmask;

import java.io.IOException;

import min3d.core.RendererActivity;
import min3d.core.Object3dContainer;
import min3d.parser.IParser;
import min3d.parser.Parser;
import min3d.vos.Light;
import min3d.vos.Number3d;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;

import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.Gallery;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

public class ArMaskActivity extends RendererActivity implements OnClickListener {
	
	private CameraSurfaceView mCameraView;
	private FrameLayout mFlPreivew;
	private ImageButton mIbArLeft, mIbArUp, mIbArDown, mIbArRight, mIbArFrontCam;
	private Gallery mGlMask;

	private Object3dContainer mMaskObject3D;
	private float mAngle, mXpos, mYpos, mTouchTurn, mTouchTurnUp, mBaseRatio;
	private float mRatio = 0.01f;
	private int mBaseDist, IPosition;
	private final static float STEP = 800;

	private int[] mask_list = new int[] {
			// on gallery sample front masks, it's 25 masks below
			R.drawable.mask_tiger_1, R.drawable.mask_tiger_2,
			R.drawable.mask_tiger_3, R.drawable.mask_tiger_4,
			R.drawable.mask_tiger_5,

			R.drawable.mask_rabbit_1, R.drawable.mask_rabbit_2,
			R.drawable.mask_rabbit_3, R.drawable.mask_rabbit_4,
			R.drawable.mask_rabbit_5,

			R.drawable.mask_girl_1, R.drawable.mask_girl_2,
			R.drawable.mask_girl_3, R.drawable.mask_girl_4,
			R.drawable.mask_girl_5,

			R.drawable.mask_boy_1, R.drawable.mask_boy_2,
			R.drawable.mask_boy_3, R.drawable.mask_boy_4,
			R.drawable.mask_boy_5,

			R.drawable.mask_egg_1, R.drawable.mask_egg_2,
			R.drawable.mask_egg_3, R.drawable.mask_egg_4, R.drawable.mask_egg_5 };

	private static final String CURRENT_POSITION = "current_position";
	private int mCurrentPosition = 0;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.ar_mask);

		mCameraView = new CameraSurfaceView(getApplicationContext());
		mFlPreivew = (FrameLayout) findViewById(R.id.fl_preview);
		mFlPreivew.addView(mCameraView);

		mIbArLeft = (ImageButton) findViewById(R.id.ib_ar_left);
		mIbArLeft.setOnClickListener(this);
		mIbArUp = (ImageButton) findViewById(R.id.ib_ar_up);
		mIbArUp.setOnClickListener(this);
		mIbArDown = (ImageButton) findViewById(R.id.ib_ar_down);
		mIbArDown.setOnClickListener(this);
		mIbArRight = (ImageButton) findViewById(R.id.ib_ar_right);
		mIbArRight.setOnClickListener(this);
		mIbArFrontCam = (ImageButton) findViewById(R.id.ib_ar_frontcam);
		mIbArFrontCam.setOnClickListener(this);

		// sample front mask list
		mGlMask = (Gallery) findViewById(R.id.gl_mask_gallery);

		// declare the gallery view
		// use the position and list item of sample front mask array
		mGlMask.setAdapter(new ImageAdapter(this));

		mGlMask.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
				IPosition = position;

				mFlPreivew.removeAllViews();
				mFlPreivew.addView(_glSurfaceView);
				mFlPreivew.addView(mCameraView);
			}
		});
	}

	// 3D Mask Resume, Pause
	@Override
	protected void onResume() {
		super.onResume();
		_glSurfaceView.onResume();
	}

	@Override
	protected void onPause() {
		super.onPause();
		_glSurfaceView.onPause();
	}

	// 3D Mask definition
	@Override
	public void initScene() {
		scene.lights().add(new Light());
		scene.lights().add(new Light());
		Light myLight = new Light();
		myLight.position.setZ(0);
		scene.lights().add(myLight);
		scene.backgroundColor().setAll(0x00000000);

		// 3D object Mapping
		IParser myParser1 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/tiger1_obj", true);
		IParser myParser2 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/tiger2_obj", true);
		IParser myParser3 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/tiger3_obj", true);
		IParser myParser4 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/tiger4_obj", true);
		IParser myParser5 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/tiger5_obj", true);
		IParser myParser6 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/rabbit1_obj", true);
		IParser myParser7 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/rabbit2_obj", true);
		IParser myParser8 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/rabbit3_obj", true);
		IParser myParser9 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/rabbit4_obj", true);
		IParser myParser10 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/rabbit5_obj", true);
		IParser myParser11 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/woman1_obj", true);
		IParser myParser12 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/woman2_obj", true);
		IParser myParser13 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/woman3_obj", true);
		IParser myParser14 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/woman4_obj", true);
		IParser myParser15 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/woman5_obj", true);
		IParser myParser16 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/man1_obj", true);
		IParser myParser17 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/man2_obj", true);
		IParser myParser18 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/man3_obj", true);
		IParser myParser19 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/man4_obj", true);
		IParser myParser20 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/man5_obj", true);
		IParser myParser21 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/egg1_obj", true);
		IParser myParser22 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/egg2_obj", true);
		IParser myParser23 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/egg3_obj", true);
		IParser myParser24 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/egg4_obj", true);
		IParser myParser25 = Parser.createParser(Parser.Type.OBJ,
				getResources(), "com.funteam.funmask:raw/egg5_obj", true);

		// 3D Mask uploading when user click a mask
		switch (IPosition) {
		case 0:
			myParser1.parse();
			mMaskObject3D = myParser1.getParsedObject();
			break;
		case 1:
			myParser2.parse();
			mMaskObject3D = myParser2.getParsedObject();
			break;
		case 2:
			myParser3.parse();
			mMaskObject3D = myParser3.getParsedObject();
			break;
		case 3:
			myParser4.parse();
			mMaskObject3D = myParser4.getParsedObject();
			break;
		case 4:
			myParser5.parse();
			mMaskObject3D = myParser5.getParsedObject();
			break;
		case 5:
			myParser6.parse();
			mMaskObject3D = myParser6.getParsedObject();
			break;
		case 6:
			myParser7.parse();
			mMaskObject3D = myParser7.getParsedObject();
			break;
		case 7:
			myParser8.parse();
			mMaskObject3D = myParser8.getParsedObject();
			break;
		case 8:
			myParser9.parse();
			mMaskObject3D = myParser9.getParsedObject();
			break;
		case 9:
			myParser10.parse();
			mMaskObject3D = myParser10.getParsedObject();
			break;
		case 10:
			myParser11.parse();
			mMaskObject3D = myParser11.getParsedObject();
			break;
		case 11:
			myParser12.parse();
			mMaskObject3D = myParser12.getParsedObject();
			break;
		case 12:
			myParser13.parse();
			mMaskObject3D = myParser13.getParsedObject();
			break;
		case 13:
			myParser14.parse();
			mMaskObject3D = myParser14.getParsedObject();
			break;
		case 14:
			myParser15.parse();
			mMaskObject3D = myParser15.getParsedObject();
			break;
		case 15:
			myParser16.parse();
			mMaskObject3D = myParser16.getParsedObject();
			break;
		case 16:
			myParser17.parse();
			mMaskObject3D = myParser17.getParsedObject();
			break;
		case 17:
			myParser18.parse();
			mMaskObject3D = myParser18.getParsedObject();
			break;
		case 18:
			myParser19.parse();
			mMaskObject3D = myParser19.getParsedObject();
			break;
		case 19:
			myParser20.parse();
			mMaskObject3D = myParser20.getParsedObject();
			break;
		case 20:
			myParser21.parse();
			mMaskObject3D = myParser21.getParsedObject();
			break;
		case 21:
			myParser22.parse();
			mMaskObject3D = myParser22.getParsedObject();
			break;
		case 22:
			myParser23.parse();
			mMaskObject3D = myParser23.getParsedObject();
			break;
		case 23:
			myParser24.parse();
			mMaskObject3D = myParser24.getParsedObject();
			break;
		case 24:
			myParser25.parse();
			mMaskObject3D = myParser25.getParsedObject();
			break;
		}

		// 3D Mask's basic position, scale
		mMaskObject3D.position().x = 0;
		mMaskObject3D.position().y = -0.7f;
		mMaskObject3D.position().z = 0;

		mMaskObject3D.scale().x = mMaskObject3D.scale().y = mMaskObject3D.scale().z = 0.7f;

		Number3d target = scene.camera().target;
		Number3d cp = scene.camera().position.clone(); // move position like
														// target is (0,0,0)
		cp.x -= target.x;
		cp.y -= target.y;
		cp.z -= target.z;
		cp.rotateX(mAngle); // restore offset
		cp.x += target.x;
		cp.y += target.y;
		cp.z += target.z;
		scene.camera().position.setAllFrom(cp);

		scene.addChild(mMaskObject3D);
	}

	// 3D Mask TouchEvent(scale, rotation)
	public boolean onTouchEvent(MotionEvent me) {
		try{
		if (me.getAction() == MotionEvent.ACTION_DOWN) {
			mXpos = me.getX();
			mYpos = me.getY();
			return true;
		}
		if (me.getAction() == MotionEvent.ACTION_UP) {
			mXpos = -1;
			mYpos = -1;
			mTouchTurn = 0;
			mTouchTurnUp = 0;
			return true;
		}
		if (me.getAction() == MotionEvent.ACTION_MOVE) {
			float xd = me.getX() - mXpos;
			float yd = me.getY() - mYpos;
			mXpos = me.getX();
			mYpos = me.getY();
			mTouchTurn = xd / -200f;
			mTouchTurnUp = yd / -200f;
			return true;
		}
		if (me.getPointerCount() == 2) {
			int action = me.getAction();
			int pureaction = action & MotionEvent.ACTION_MASK;
			if (pureaction == MotionEvent.ACTION_POINTER_DOWN) {
				mBaseDist = getDistance(me);
				mBaseRatio = mRatio;
			} else {
				float delta = (getDistance(me) - mBaseDist) / STEP;
				float multi = (float) Math.pow(2, delta);
				mRatio = Math.min(1.0f, Math.max(0.3f, mBaseRatio * multi));

				Matrix m = new Matrix();
				m.postScale(mRatio, mRatio);
				mMaskObject3D.scale().x = mMaskObject3D.scale().y = mMaskObject3D
						.scale().z = mRatio;

			}
		}
	}
		 catch (Exception e) {
		}

		return super.onTouchEvent(me);
	}

	int getDistance(MotionEvent me) {
		int dx = (int) (me.getX(0) - me.getX(1));
		int dy = (int) (me.getY(0) - me.getY(1));
		return (int) (Math.sqrt(dx * dx + dy * dy));
	}

	@Override
	public void updateScene() {
		if (mTouchTurn != 0) {
			scene.camera().position.rotateY(mTouchTurn);
			mTouchTurn = 0;
		}
		if (mTouchTurnUp != 0) {
			scene.camera().position.rotateX(mTouchTurnUp);
			mTouchTurnUp = 0;
		}
	}

	// use imageadapter -> it's for return sample front mask values return
	public class ImageAdapter extends BaseAdapter {
		int mGalleryItemBackground;
		private Context mContext;

		public ImageAdapter(Context c) {
			mContext = c;

		}

		public int getCount() {
			return mask_list.length;
		}

		public Object getItem(int position) {
			return position;
		}

		public long getItemId(int position) {
			return position;
		}

		public View getView(int position, View convertView, ViewGroup parent) {
			ImageView i = new ImageView(mContext);

			i.setImageResource(mask_list[position]);
			i.setLayoutParams(new Gallery.LayoutParams(200, 120));
//			i.setLayoutParams(new Gallery.LayoutParams(150,100)); //Galaxy Note
			//i.setLayoutParams(new Gallery.LayoutParams(120, 80)); // Galaxy S2,
																	// S2 LTE
			i.setScaleType(ImageView.ScaleType.FIT_CENTER); // how to crop?
			i.setBackgroundColor(mGalleryItemBackground);
			return i;
		}

	}

	// preview's Surfaceview Class Definition
	/*
	 * Camera SurfaceView
	 */
	// Control SurfaceView's Surface object using Surfaceholder.Callback
	@SuppressLint("NewApi")
	public class CameraSurfaceView extends SurfaceView implements
			SurfaceHolder.Callback {

		boolean isFrontCamera; // for opening front camera
		SurfaceHolder mHolder = null; // for preview camera
		Camera camera = null;

		public CameraSurfaceView(Context context) {
			super(context);

			mHolder = getHolder();
			mHolder.addCallback(this);
			mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		}

		// set up preview and open camera when create surfaceview
		public void surfaceCreated(SurfaceHolder holder) {

			try {
				camera = Camera.open();
				camera.setDisplayOrientation(90);
				camera.setPreviewDisplay(holder);

				Camera.Parameters p = camera.getParameters();
				p.set("camera_id", 2);
				camera.setParameters(p);

			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		// ///////////////////////////// front camera start /////////////////////////////
		public Camera openCamera(int facing) {

			int cameraCount = -1;
			Camera cam = null;
			Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
			cameraCount = Camera.getNumberOfCameras();

			for (int cameraId = 0; cameraId < cameraCount; cameraId++) {

				Camera.getCameraInfo(cameraId, cameraInfo);

				if (cameraInfo.facing == facing) {

					try {
						cam = Camera.open(cameraId);
						break;
					} catch (RuntimeException e) {
						e.printStackTrace();
					}
				}
			}
			return cam;
		}

		public void startCamera(int facing) {

			camera = openCamera(facing);
			camera.setDisplayOrientation(90);

			if (camera == null) {

				camera = Camera.open();
				isFrontCamera = false;

			}

			try {

				camera.setPreviewDisplay(mHolder);

			} catch (IOException e) {
				Log.e("CameraSurfaceView", "Failed to set camera preview.", e);
			}
		}

		public void closeCamera() {

			if (camera != null) {

				camera.stopPreview();
				camera.setPreviewCallback(null);
				camera.release();
				camera = null;
			}
		}

		// exchange front camera and back camera
		public void changeCamera() {

			closeCamera();
			isFrontCamera = !isFrontCamera;

			if (isFrontCamera) {
				startCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);

			} else {
				startCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
			}
			camera.startPreview();

		}

		
		// ///////////////////////////// front camera finish /////////////////////////////
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {
			Camera.Parameters parameters = camera.getParameters();
			// Bring all devices' supported screen size and select the biggest size
			// Setup preview size
			camera.setParameters(parameters);
			// Draw preview on surfaceview
			camera.startPreview();
		}

		public void surfaceDestroyed(SurfaceHolder holder) {
			camera.stopPreview();
			camera.release();
			camera = null;
		}

		// capture surfaceview
		public boolean capture(final Camera.PictureCallback handler) {

			if (camera != null) {
				
				camera.startPreview();
				camera.autoFocus(null);
				camera.takePicture(null, null, handler);
				return true;
				
			} else {
				return false;
			}

		}

	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		if (outState == null) {
			return;
		}
		outState.putInt(CURRENT_POSITION, mCurrentPosition);
	}

	@Override
	public void onClick(View v) {
		switch(v.getId()) {
		
		case R.id.ib_ar_left:
			try {
				mMaskObject3D.position().x -= 0.1f;
			} catch (Exception e) {
				System.out.println("There is no Object.");
				Toast.makeText(ArMaskActivity.this, "Please Select Mask.",
						Toast.LENGTH_SHORT).show();
			}
			break;
		case R.id.ib_ar_up:
			try {
				mMaskObject3D.position().y += 0.1f;
			} catch (Exception e) {
				System.out.println("There is no Object.");
				Toast.makeText(ArMaskActivity.this, "Please Select Mask.",
						Toast.LENGTH_SHORT).show();
			}
			break;
		case R.id.ib_ar_down:
			try {
				mMaskObject3D.position().y -= 0.1f;
			} catch (Exception e) {
				System.out.println("There is no Object.");
				Toast.makeText(ArMaskActivity.this, "Please Select Mask.",
						Toast.LENGTH_SHORT).show();
			}
			break;
		case R.id.ib_ar_right:
			try {
				mMaskObject3D.position().x += 0.1f;
			} catch (Exception e) {
				System.out.println("There is no Object.");
				Toast.makeText(ArMaskActivity.this, "Please Select Mask.",
						Toast.LENGTH_SHORT).show();
			}
			break;
		case R.id.ib_ar_frontcam:
			mCameraView.changeCamera();
			break;
		}
	}

}
